home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Tele / T / Toolkit.cpt / RCMD's For White Knight < prev    next >
Encoding:
Text File  |  1990-01-07  |  17.1 KB  |  390 lines  |  [TEXT/MWII]

  1. RCMD's For White Knight 11
  2.  
  3. White Knight 11 has a very special type of feature that adds a tremendous amount of flexibility to your Procedure files.  This feature allows White Knight 11's Procedure language to be extended with user-written commands, much like Hypercard's XCMD's.  In fact, White Knight's user-written commands are given the generic name "RCMD" (pronounced "r-command").
  4.  
  5. What Is An RCMD?
  6.  
  7. An RCMD is simply an executable code resource, with the resource type 'RCMD', much like the types 'MDEF' and 'WDEF' described in Inside Macintosh.  If your particular language compiler can create a 'MDEF' resource, it is almost certain that you can use it to create an 'RCMD' resource.  The 'RCMD' resource, along with any other resources the RCMD might need, is placed in the resource fork of the Procedure which calls it.  A Procedure File can contain as many different RCMD's as you wish, but any conflicts between resource numbers are entirely up to you to resolve.  Therefore, if you are developing RCMD's that might be of use to others, you might want to consider putting each RCMD in a Procedure File of its own, terminated with a NESTEND command.  By doing this, Procedure developers could take advantage of the NEST command to call your RCMD without worrying about resource number conflicts with other RCMD's in the same Procedure file.
  8.  
  9. The RCMD is called Pascal style with one longint parameter as an argument.  This is a pointer to a special parameter block containing many different variables important to White Knight (and perhaps your RCMD).  No parameters are returned by the RCMD.
  10.  
  11. The Mechanics Of Calling An RCMD
  12.  
  13. For a Procedure to call an RCMD, it is necessary to use only one special Procedure command:
  14.  
  15. RCMD num_exp1,num_exp2
  16. Description: This command executes the RCMD whose resource ID number is contained in num_exp2.  The RCMD itself is contained in the resource fork of the Procedure file.  The parameter num_exp1 will be either 0 (zero) or 1 (one).
  17. If the RCMD opens any windows or installs any menus, it must pass zero for num_exp1.  This tells White Knight to close its windows and deinstall its menus before executing the RCMD.  This is necessary because it would be impossible to update or activate/deactivate any of White Knight's windows from within the RCMD, and your RCMD would not know the present state of any of White Knight's menus.  When the RCMD completes, White Knight's windows and menus are redisplayed as before.  If your RCMD does not require any user input/output and does not do any drawing, you can pass a 1 for num_exp1 and the RCMD will be quite transparent to the user.
  18.  
  19. The sample RCMD's provided with White Knight 11 show the versatility of this feature.  RCMD's can manipulate their own menus, support desk accessories and MultiFinder, and provide their own graphic interface to
  20. the user.
  21.  
  22. The Down And Dirty Aspects Of RCMD's
  23.  
  24. If an RCMD were documented in Inside Macintosh style, it would appear like this:
  25.  
  26. MyRCMD(RPtr: params);
  27.  
  28. in C language, it would be documented like this:
  29.  
  30. pascal void MyRCMD(params)
  31. RPtr params;
  32.  
  33. The RPtr parameter is a pointer to a structure that's rather complex and includes most everything I could think of that you might want access to in your routines.  PLEASE DON'T BE PUT OFF BY THE SIZE OF THIS THING!  Your RCMD might not have any need of any of the following, in which case you could just ignore the RPtr value that's passed.
  34.  
  35. In C language format, the structure would look like this:
  36.  
  37. typedef struct
  38.     
  39.     {
  40.     NumVarPtr    Numeric;
  41.     StrVarPtr    String;
  42.     WKPtr    WKParams;
  43.     Ptr    Reserved1;
  44.     long    Reserved2;
  45.     long    Reserved3;
  46.     long    Reserved4;
  47.     short    Reserved5;
  48.     ParmBlkPtr    UserBlock1;
  49.     ParmBlkPtr    UserBlock2;
  50.     ParmBlkPtr    SerialIn;
  51.     ParmBlkPtr    SerialOut;
  52.     Byte20Ptr    RadioGroup;
  53.     Byte20Ptr    CheckBox;
  54.     Ptr1K    Buffer1K;
  55.     Ptr2K    Buffer2K;
  56.     FilterPtr    TFilter;
  57.     FilterPtr    FFilter;
  58.     FilterPtr    PFilter;
  59.     FlagPtr    Flags;
  60.     Ptr123    RecPath;
  61.     RGBColor    Forecolor;
  62.     RGBColor    Backcolor;
  63.     RGBColor    Hilcolor;
  64.     RGBColor    SBfore;
  65.     RGBColor    SBback;
  66.     RGBColor    SBhil;
  67.     RGBColor    Phonefore;
  68.     RGBColor    Phoneback;
  69.     RGBColor    Phonehil;
  70.     RGBColor    Indfore;
  71.     RGBColor    Indback;
  72.     RGBColor    Rlefore;
  73.     RGBColor    Rleback;
  74.     WindowPeek    WKsWindow;
  75.     short    DoUpdate;
  76.     Rect    TransferRect;
  77.     short    Version;
  78.     } RPtr,*RParam;
  79.  
  80. We'll now look at each of the components of this structure.
  81. Numeric
  82. This is a pointer to a structure that looks like this:
  83. typedef struct
  84.     {
  85.     long    thenum[234];
  86.     } NumVar,*NumVarPtr;
  87. The parameter thevar is an array of 234 long integers, each containing the current values of the numeric variables A1% to Z9% in that order.  The structure is ordered so that the first 26 elements are A1% through Z1%, the next 26 elements would be A2% through Z2%, and the last 26 elements would be A9% through Z9%.
  88.  
  89. String
  90. This is a pointer to a structure that looks like this:
  91. typedef struct
  92.     {
  93.     Byte    thestr[234][134];
  94.     } Strings,*StrVarPtr;
  95. The parameter thestr is an array of 234 Pascal type strings of 134 characters each (including the length byte), containing the current contents of the string variables A1$ to Z9$ in that order.  The structure is ordered so that the first 26 elements are A1$ through Z1$, the next 26 elements would be A2$ through Z2$, and the last 26 elements would be A9$ through Z9$.
  96.  
  97. WKParam
  98. This is a pointer to a structure that looks like this:
  99. typedef struct
  100.     {
  101.     Byte    theparam[8350];
  102.     } WKParam,*WKPtr;
  103. The parameter theparam is an array of 8350 bytes, which corresponds to the values you would use with the Procedure command GETPARAM and PUTPARAM.  The same rules as to reading or writing these values must be followed as for the GETPARAM and PUTPARAM commands.
  104.  
  105. Reserved1, Reserved2, Reserved3, Reserved4, Reserved5
  106. These values are used internally and should not be used or written to by your RCMD.
  107.  
  108. UserBlock1 and UserBlock2
  109. The ParmBlkPtr structure is documented on page II-98 of Inside Macintosh.  UserBlock1 and UserBlock2 point to the two structures used with the Procedure commands USEROPENI, USEROPENO, USEROPENA, USERCLOSE, USERWRITE, USERREAD, and USERWRCR (corresponding to the two paths available to these commands).
  110.  
  111. SerialIn and SerialOut
  112. The ParmBlkPtr structure is documented on page II-98 of Inside Macintosh.  SerialIn points to the structure White Knight has allocated for reading input from the currently open serial port.  SerialOut points to the structure White Knight has allocated for writing to the currently open serial port.
  113.  
  114. RadioGroup And CheckBox
  115. These two parameter point to a structure that looks like this:
  116. typedef struct
  117.     
  118.     {
  119.     Byte    theval[20];
  120.         } Byte20,*Byte20Ptr;
  121. The structure pointed to by RadioGroup structure represents the 20 bytes allocated for use with the GETGROUP and SETGROUP Procedure commands.  The structure pointed to by CheckBox represents the 20 bytes allocated for use with the SETBOX and GETBOX Procedure commands.
  122.  
  123. Buffer1K and Buffer2K
  124. Buffer1K points to a structure that looks like this:
  125. typedef struct
  126.     {
  127.     Byte    data[1024];
  128.     } Buff1K,*Ptr1K;
  129. Buffer2K points to a structure that looks like this:
  130. typedef struct
  131.     
  132.     {
  133.     Byte    data[2048];
  134.     } Buff2K,*Ptr2K;
  135. These two items point to buffers of 1K bytes and 2K bytes allocated by White Knight.  You are free to use them for any purpose you wish.  They are especially attractive if free memory is unknown or known to be small.
  136.  
  137. TFilter, FFilter, And PFilter
  138. These three parameters point to a structure that looks like this:
  139. typedef struct
  140.     {
  141.     Byte    thechar[256][2];
  142.     } Filter,*FilterPtr;
  143. This structure represents a 2 byte entry for each of the possible 256 ASCII codes.  The first byte tells you how to filter received bytes of that value.  0 means let it pass through, 1 means strip it out, 2 means to replace it with a byte of the value in the 2nd byte entry. and 3 means to enumerate it.  TFilter points to the currently installed Terminal Filter.  FFilter points to the currently installed File Capture Filter.  PFilter points to the currently installed Protocol Transfer Filter.
  144.  
  145. Flags
  146. This parameter points to a structure that looks like this:
  147. typedef struct
  148.     {
  149.     Byte    YesNoFlag;
  150.     Byte    ErrorFlag;
  151.     } FlagRec,*FlagPtr;
  152. The YesNoFlag flag is used by the IF YES and IF NO Procedure commands.  Set it to zero to mean NO or one to mean YES.  The ErrorFlag is used by the IF ERROR and IF NO ERROR Procedure commands.  Set it to zero to mean NO ERROR or one to mean ERROR.
  153.  
  154. RecPath
  155. This parameter points to a structure that looks like this:
  156. typedef struct
  157.     {
  158.     Byte    thepath[124];
  159.     } Byte124,*Ptr124;
  160. The parameter thepath is a Pascal type string of up to 124 characters (including the length byte) that contains the current Received File Destination path.
  161.  
  162. Colors
  163. There are 13 parameters that are structures (not pointers to structures) that looks like this:
  164.  
  165. typedef struct
  166.     
  167.     {
  168.     unsigned short    red;
  169.     unsigned short    green;
  170.     unsigned short    blue;
  171.      } RGBColor;
  172. This structure is described on page V-48 of Inside Macintosh.  They are the colors used by White Knight for the following purposes:
  173. Forecolor: terminal window foreground color.
  174. Backcolor: terminal window background color.
  175. Hilcolor: terminal window hilite color.
  176. SBfore: status bar foreground color.
  177. SBback: status bar background color.
  178. SBhil: status bar hilite color.
  179. Phonefore: phonebook foreground color.
  180. Phoneback: phonebook background color.
  181. Phonehil: phonebook hilite color.
  182. Indfore: file transfer indicator foreground color.
  183. Indback: file transfer indicator background color.
  184. Rlefore: RLE graphics foreground color.
  185. Rleback: RLE graphics background color.
  186. These colors would be used by your RCMD to provide a consistent interface to the user.  For instance, in the "QUICKB" RCMD, I use both the Indfore and Indback values to stay consistent with what White Knight's built in protocols would use.
  187.  
  188. WKsWindow
  189. The WindowPeek structure is documented on page I-304 of Inside Macintosh.  Note that if White Knight is running on a machine that supports Color Quickdraw, this parameter will be a CWindowPeek type parameter, which is documented on page V-199 of Inside Macintosh.  WKsWindow is simply a pointer to the terminal window.
  190.  
  191. DoUpdate
  192. This parameter is an integer.  If your RCMD does any drawing in WKsWindow, it should set this parameter to non-zero, so that White Knight will correctly redraw the terminal window when your RCMD finishes.
  193.  
  194. TransferRect
  195. This parameter is a Rect structure, which is described on page I-141 of Inside Macintosh.  This parameter is the global coordinates of the last position of the file transfer window, should you decide to try and duplicate the appearance of that window.
  196.  
  197. Version
  198. This integer will hold a version number of the structure pointed to by RPtr so that additional items can be added in future versions of White Knight.  The version number for the structure described in this document is zero.
  199.  
  200. Register Usage
  201. LightSpeed C users will not have to do anything special, but for assembly language (and some other languages), programmers may destroy the contents of only registers D0,D1,D2, A0, and A1.  The contents of all other registers must be preserved.  Remember that your resource is being called with the RPtr argument being passed Pascal style, just as if your resource was a MDEF or WDEF..  If your RCMD uses global variables, you'll probably need to do something to make the A5 or A4 register point to them upon entry to your RCMD.  In LightSpeed C, for instance, global variables in a CODE resource are referenced off of A4, so the LightSpeed C routines RememberA0, SetUpA4, and RestoreA4 are used at the beginning and end (respectively) of the RCMD that uses global variables.
  202.  
  203. Sample RCMD Code
  204. The following is a small RCMD that demonstrates how such a thing is put together, as well as how to access White Knight 11's variables.  All of the following is for LightSpeed C.
  205.  
  206. /* File Speak.c */
  207. #include "MacTypes.h"
  208. #include "MemoryMgr.h"
  209. #include "OSUtil.h"
  210. #include "pascal.h"
  211. #include "SegmentLdr.h"
  212. #include "ToolboxUtil.h"
  213. #include "Macintalk.h"
  214. #include "QuickDraw.h"
  215. #include "DeviceMgr.h"
  216. #include "FileMgr.h"
  217. #include "WindowMgr.h"
  218. /* Lightspeed C sez this should always be the last #included file */
  219. #include "SetUpA4.h"
  220.  
  221. typedef struct
  222.     {
  223.     long    thenum[26];
  224.     } NumVar,*NumVarPtr;
  225.  
  226. typedef struct
  227.     {
  228.     Byte    thestr[26][134];
  229.     } Strings,*StrVarPtr;
  230.  
  231. typedef struct
  232.     {
  233.     Byte    theparam[8350];
  234.     } WKParam,*WKPtr;
  235.  
  236. typedef struct
  237.     {
  238.     Byte    theval[20];
  239.     } Byte20,*Byte20Ptr;
  240.  
  241. typedef struct
  242.     {
  243.     Byte    data[1024];
  244.     } Buff1K,*Ptr1K;
  245.  
  246. typedef struct
  247.     {
  248.     Byte    data[2048];
  249.     } Buff2K,*Ptr2K;
  250.  
  251. typedef struct
  252.     {
  253.     Byte    thechar[256][2];
  254.     } Filter,*FilterPtr;
  255.  
  256. typedef struct
  257.     {
  258.     Byte    YesNoFlag;
  259.     Byte    ErrorFlag;
  260.     } FlagRec,*FlagPtr;
  261.  
  262. typedef struct
  263.     {
  264.     Byte    thepath[124];
  265.     } Byte124,*Ptr124;
  266.  
  267. typedef struct
  268.     {
  269.     unsigned short    red;
  270.     unsigned short    green;
  271.     unsigned short    blue;
  272.     } RGBColor;
  273.  
  274. typedef struct
  275.     {
  276.     NumVarPtr    Numeric;
  277.     StrVarPtr    String;
  278.     WKPtr        WKParams;
  279.     Ptr        Reserved1;
  280.     long        Reserved2;
  281.     long        Reserved3;
  282.     long        Reserved4;
  283.     short        Reserved5;
  284.     ParmBlkPtr    UserBlock1;
  285.     ParmBlkPtr    UserBlock2;
  286.     ParmBlkPtr    SerialIn;
  287.     ParmBlkPtr    SerialOut;
  288.     Byte20Ptr    RadioGroup;
  289.     Byte20Ptr    CheckBox;
  290.     Ptr1K        Buffer1K;
  291.     Ptr2K        Buffer2K;
  292.     FilterPtr    TFilter;
  293.     FilterPtr    FFilter;
  294.     FilterPtr    PFilter;
  295.     FlagPtr        Flags;
  296.     Ptr124        RecPath;
  297.     RGBColor        Forecolor;
  298.     RGBColor        Backcolor;
  299.     RGBColor        Hilcolor;
  300.     RGBColor        SBfore;
  301.     RGBColor        SBback;
  302.     RGBColor        SBhil;
  303.     RGBColor        Phonefore;
  304.     RGBColor        Phoneback;
  305.     RGBColor        Phonehil;
  306.     RGBColor        Indfore;
  307.     RGBColor        Indback;
  308.     RGBColor        Rlefore;
  309.     RGBColor        Rleback;
  310.     WindowPeek    WKsWindow;
  311.     short        DoUpdate;
  312.     Rect        TransferRect;
  313.     short        Version;
  314.     } RParam,*RPtr;
  315.  
  316. /* Globals used in this resource */
  317. short SPitch,SRate;
  318. Handle MTHand;
  319. short OSerr;
  320. Handle SHand;
  321. short z;
  322.  
  323.  
  324. /*
  325. Speak text in T1$ using Macintalk, using SpeechPitch P1%, SpeechRate R1%, and Exceptions File F1$ (which should be blank if no exceptions).  M1% specifies the mode: 0 = Natural, 1 = Robotic.
  326. */
  327.  
  328. /* Start of code resource */
  329. pascal void main(params)
  330. RPtr params;
  331. {
  332. /*
  333. Following two instructions preserve the contents of register A4
  334. coming in and set up A4 to point to our globals.  Yes, this could have
  335. been done with local variables, but I want to demonstrate that globals
  336. are possible if your compiler supports them with CODE resources like
  337. LightSpeed C.  RememberA0(), SetUpA4(), and RestoreA4() are LightSpeed
  338. C private functions - your compiler may not support them or there may be equivalent functions for accessing global variables inside of a CODE resource. 
  339. */
  340.  
  341. RememberA0();
  342. SetUpA4();
  343. SHand = NewString("\Px");
  344. SPitch = (short)params->Numeric->thenum[15]; /* P1% */
  345. SRate = (short)params->Numeric->thenum[17]; /* R1% */
  346. if (OSerr = SpeechOn(params->String->thestr[5],&MTHand)) /* F1$ */
  347.     {
  348.     SysBeep(5);
  349.     goto EXIT;
  350.     }
  351. if (params->Numeric->thenum[12]) SpeechPitch(MTHand,SPitch,Robotic);
  352. /* M1% */
  353. else SpeechPitch(MTHand,SPitch,Natural);
  354. SpeechRate(MTHand,SRate);
  355. Reader(MTHand,¶ms->String->thestr[19][1],
  356.     (long)params->String->thestr[19][0],SHand); /* T1$ */
  357. OSerr = MacinTalk(MTHand,SHand);
  358. SpeechOff(MTHand);
  359. EXIT:
  360. DisposHandle(SHand);
  361. /* Folowing instruction restores register A4 to what it was before we entered here. */
  362. RestoreA4();
  363. }
  364. /* End of Speak.c */
  365.  
  366.  
  367. Putting This Together
  368. In LightSpeed C, you should create a new project containing the libraries "MacTraps", and "Macintalk.Lib" and the source code file "Speak.c" (above).  Go to LightSpeed C's "Project" menu and choose "Set Project Type...".  In the dialog box that comes up, you should select the radio button marked "Code resource".  For the "Type" item, type in "RCMD".  For the "ID" item, type in the number "202".  Now under the "Project" menu, choose "Build Code Resource".  After the libraries are loaded and the source code file is compiled, you'll be prompted to enter a filename the resource is to be placed in.  Type in "Speak.CODE".
  369.  
  370. Now, we'll need to build a Procedure file to set up the proper variables and call our RCMD.  The following Procedure commands should be entered, and compiled to the file "Speak.PROC".
  371.  
  372. (Speak text in T$, using SpeechPitch P%, SpeechRate R%, and Exceptions)
  373. (File F$.  M% specifies the mode: 0 = Natural, 1 = Robotic.)
  374. ERASE T$
  375. ERASE F$
  376. LET EQUAL P%,150
  377. LET EQUAL R%,125
  378. LET EQUAL M%,0
  379. RCMD 1,202
  380. COPYINTO T$,This is a test of White Knight speaking to me.
  381. RCMD 1,202
  382. NESTEND
  383. Finally, using ResEdit, copy the RCMD resource from "Speak.CODE" to "Speak.PROC".  In White Knight 11, run the Procedure "Speak.PROC" to see how it works.
  384.  
  385. Using Resources With RCMD's
  386. Although our sample RCMD above doesn't do any window or menu manipulation, this is entirely possible (check out ProcEdit, which even supports desk accessories).  If your RCMD requires any resources, simply copy them into the Procedure file's resource fork along with the RCMD resource. HINT: once the RCMD is developed and you will be doing further development only on the Procedure source code, you can save a lot of time by copying the RCMD resource (and any resources the RCMD uses) to the source code file of the Procedure.  This is because White Knight's Procedure compiler will automatically copy any resources in the source code file to the executable Procedure file and you'll therefore save a step with ResEdit for each compile.
  387.  
  388. Special Warning
  389. If you choose to support an Apple menu, it must be given a menu ID number of 201 and it must begin with an "About..." item followed by a disabled gray line.  If these rules are not observed, your RCMD will not support MultiFinder and desk accessories correctly.
  390.